﻿#include "FITKCCXAdaptorSet.h"
#include "FITKCalculiXINPWriter.h"
#include "FITKCalculiXINPReader.h"
#include "InpKeyLineSpliter.h"
#include "FITK_Interface/FITKInterfaceModel/FITKModelSet.h"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"

#include <QTextStream>

//set集合每行不得超过16个，INP准则
#define SETCOUNT 16

namespace IO
{

    QString FITKCCXAdaptorSet::getAdaptorClass()
    {
        return "IO::FITKCCXAdaptorSet";
    }

    void FITKCCXAdaptorSet::setCaseData(AbaqusData::FITKDataCase * caseData)
    {
        _caseData = caseData;
    }

    void FITKCCXAdaptorSet::setAssemblyPartManager(Interface::FITKAbaAssembly * ass, AbaqusData::FITKAbaqusPartManager * part)
    {
        // 设置装配管理器
        _assemblyManager = ass;

        // 设置部件管理器
        _partManager = part;
    }

    void FITKCCXAdaptorSet::setModelInfoManager(FITKCCXModelInforManager * modelInfoManager)
    {
        _modelInfoManager = modelInfoManager;
    }

    void FITKCCXAdaptorSet::setMappingKeyObjectDataID(const int & objectDataID)
    {
        _mappingKeyParentID = objectDataID;
    }

    void FITKCCXAdaptorSet::setAssemblyManager(Interface::FITKAbaAssembly * ass)
    {
        _assemblyManager = ass;
    }

    void FITKCCXAdaptorSet::setSetNumber(const int & setNumber)
    {
        _setNumber = setNumber;
    }

    int FITKCCXAdaptorSet::getSetNumber()
    {
        return _setNumber;
    }

    bool FITKCCXAdaptorSet::adaptR()
    {
        _setData = dynamic_cast<Interface::FITKModelSet*>(_dataObj);
        if (_setData == nullptr)return false;
        if (!_setData || !_reader) return false;

        //回退一行 处理关键字信息
        _reader->backLine();

        QString line = _reader->readLine();
        QString setName;
        //处理关键字 获取基础信息
        InpKeyLineSpliter spl(line, _reader);
        QString sH = spl.getHeader().toLower();
        if (sH == "nset")
        {
            _setData->setModelSetType(Interface::FITKModelEnum::FITKModelSetType::FMSNode);
            setName = spl["nset"];   //名字
        }
        else if (sH == "elset")
        {
            _setData->setModelSetType(Interface::FITKModelEnum::FITKModelSetType::FMSElem);
            setName = spl["elset"];   //名字
        }
        _setData->setDataObjectName(setName);
        //读取set集合
        while (!_reader->atEnd())
        {
            line = _reader->readLine();
            //关键字段结束
            if (line.startsWith("*")) break;
           
            QStringList sList = line.split(",");
            for (int i = 0; i < sList.size(); ++i)
            {
                QString str = sList.at(i);
                if (str.trimmed().isEmpty()) continue;
                bool ok = false;
                int member = str.trimmed().toInt(&ok);
               if(!ok) continue;
                _setData->appendMember(member);
            }
        }
        return true;

    }

    bool FITKCCXAdaptorSet::adaptW()
    {
        // 将数据对象转换为 FITKModelSet 类型
        // _setData = Interface::FITKModelSet::SafeDownCastFITKModelSet(_dataObj);
        _setData = dynamic_cast<Interface::FITKModelSet*>(_dataObj);

        // 检查是否缺少任何必需的数据对象
        if (_setData == nullptr || _writer == nullptr || _modelInfoManager == nullptr) return false;
        bool isW = true;

        // 增加集合累加
        _setNumber++;

        // 如果数据对象是组合集合
        if (_setData->isCombination())
        {
            for (int i = 0; i < _setData->getDataCount(); ++i)
            {
                // 遍历每个子集， 将子集写入文件，并更新 isW 的值
                isW &= writeSet(_setData->getDataByIndex(i));
            }
        }
        else
        {
            // 将单个子集写入文件，并更新 isW 的值
            isW &= writeSet(_setData);
        }
        return isW;
    }

    bool FITKCCXAdaptorSet::writeSet(Interface::FITKModelSet* set)
    {
        if (set == nullptr) return false;
        // 获取文本流
        QTextStream* stream = _writer->getStream();

        // 判断是否在写出ElSet集合
        bool isELset = false;

        // 固定的关键字标记
        QString setTitle;

        // 根据集合类型设置不同的关键字标记
        if (set->getModelSetType() == Interface::FITKModelEnum::FITKModelSetType::FMSNode)
        {
            setTitle = "*Nset, nset=%1";
        }
        else if (set->getModelSetType() == Interface::FITKModelEnum::FITKModelSetType::FMSElem)
        {
            setTitle = "*Elset, elset=%1";
            isELset = true;
        }

        // 设置集合名称
        QString setName = QString("set-%1").arg(_setNumber);
        setTitle = setTitle.arg(setName);

        //添加额外的关键字标记
        if (set->isInternal())
        {
            _writer->consoleMessage(2, "Calculix does not support the keyword Internal when writing set");
        }
        if (set->getAbstractModel() != nullptr && set->getAbstractModel()->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AssInstance)
        {
            _writer->consoleMessage(2, "Calculix does not support the keyword Instance when writing set");
        }
        // 如果集合是generate格式，添加 generate 标记
        if (set->isGenerated())
        {
            setTitle += ", generate";
        }

        // 写入集合标题到文件中
        *stream << setTitle << endl;

        // 判断set集合类型进行映射关系表主键赋值
        if (set->getAbstractModel() != nullptr && set->getAbstractModel()->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AssInstance)
        {
            QString instanceName = set->getAbstractModel()->getDataObjectName();
            _mappingKeyParentID = set->getAbstractModel()->getDataObjectID();         
        }

        // 添加Set映射关系表
        QPair<int, int> setMappingKey(_mappingKeyParentID, set->getDataObjectID());
        _modelInfoManager->addSetMapping(setMappingKey, setName);

        // 获取集合成员列表
        QList<int> memberList = set->getMember();

        // 获取成员数量
        int memberListCount = memberList.size();
        if (memberListCount < 1) return false;

        //超过一行SETCOUNT个则每行SETCOUNT(16)个，否则 maberCount 作为当前行最大长度
        int lineCount = memberListCount > SETCOUNT ? SETCOUNT : memberListCount;

        // abaqus中节点值的映射结果
        int nodeMappingValue = -1;

        for (int i = 0; i < memberListCount; i += lineCount)
        {
            nodeMappingValue = getNodeMappingValue(set->isGenerated(), memberList[i], i, isELset);

            //写出每行的第一个数据
            *stream << _writer->int2String(nodeMappingValue, 8) << ",";

            //计算当前行的长度
            lineCount = memberListCount - i > SETCOUNT ? SETCOUNT : memberListCount - i;
            for (int j = 1; j < lineCount; ++j)
            {
                nodeMappingValue = getNodeMappingValue(set->isGenerated(), memberList[i + j], j, isELset);
                if (j != 1)
                    *stream << ",";
                *stream << _writer->int2String(nodeMappingValue, 8);
            }
            *stream << endl;
        }
        return true;
    }

    int FITKCCXAdaptorSet::getNodeMappingValue(const bool &isGenerateSet, const int &nodeIndex, const int &index, const bool &isElSet)
    {
        // 初始化映射节点ID
        int mappingNodeID = -1;

        // 设置节点映射关系表的主键
        QPair<int, int> nodeMappingKey(_mappingKeyParentID, nodeIndex);

        // 如果集合不是生成的或者当前索引小于2，表示需要进行映射
        if (!isGenerateSet || index < 2)
        {
            if (isElSet)
            {
                // 如果是元素集合，从元素映射关系表中获取映射节点ID
                mappingNodeID = _modelInfoManager->getElementMappingValue(nodeMappingKey);
            }
            else
            {
                // 如果是节点集合，从节点映射关系表中获取映射节点ID
                mappingNodeID = _modelInfoManager->getNodeMappingValue(nodeMappingKey);
            }
        }
        else
        {
            // 如果集合是生成的，直接将节点索引作为映射节点ID
            mappingNodeID = nodeIndex;
        }
        return mappingNodeID;
    }

    int FITKCCXAdaptorSet::getInstanceIDByName(const QString &inputInstanceName)
    {
        // 初始化实例ID
        int instanceID = -1;

        // 获取实例数量
        int instanceNum = _assemblyManager->getDataCount();
        if (instanceNum < 1) return instanceID;
        for (int i = 0; i < instanceNum; ++i)
        {
            // 获取当前实例
            auto instance = _assemblyManager->getDataByIndex(i);
            if (instance == nullptr) continue;

            // 获取实例名称
            QString instanceName = instance->getDataObjectName();
            if (instanceName == inputInstanceName)
            {
                instanceID = instance->getDataObjectID();
                break; // 找到匹配实例后，跳出循环
            }
        }
        return instanceID;
    }
}